# -*- encoding: utf-8 -*-

# Copyright 2010 István Szentandrási
# <etude-music-player@googlegroups.com>

# This file is part of Etude.
#
# Etude is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as 
# published by the Free Software Foundation, either version 3 
# of the License, or (at your option) any later version.
#
# Etude is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Etude. If not, see <http://www.gnu.org/licenses/>.

from . import _

import goocanvas as goo
import gtk
import pango
import sys
import copy

from etude.client import Collection as ec
from collection_editor import IDListView
from etude.gui import get_property_combo


class Operator(goo.Group):

    """
    Parent class for other operators
    """

    op_width = 150 
    op_height = 80
    op_name = _("Operator")
    op_type = None
    op_n_operands = sys.maxint #number of operands of the collection type
    op_n_outputs = sys.maxint #number of outputs of a collection type
    op_border_color = 0xecba2aff
    op_fill_color = 0xf0d24980
    op_rect_line_width = 1.0
    op_attr_order = []

    def __init__(self, editor, parent, x = 0, y = 0):
        goo.Group.__init__(self, parent = parent)
        self.translate(x, y)
        self.editor = editor
        self.op_attributes = {}
        self.op_operands = []
        self.op_outputs = []
        self.view_init()

    def __str__(self):
        ret_str = ''
        ret_str += '<span size="larger"><b>'+self.op_name+'</b></span>( '
        for key, value in self.op_attributes.items():
            ret_str += ' <i>'+key+'</i> = "'+str(value)+'",'
        ret_str = ret_str[:-1]+" )"
        return ret_str

    def set_focused(self, focused):
        """
        when focused change the border color and thickness
        """
        if focused:
            color = 0x8c1c95ff #cyklamen color
            border = 3.0
        else:
            color = self.op_border_color
            border = self.op_rect_line_width
        self.rect.set_property('stroke_color_rgba', color)
        self.rect.set_property('line_width', border)


    def view_init(self):
        """create the the graphical representation of an operator"""

        self.rect = goo.Rect(parent = self, 
                x = 0, 
                y = 0, 
                width = self.op_width, 
                height = self.op_height,
                fill_color_rgba = self.op_fill_color,
                stroke_color_rgba = self.op_border_color,
                line_width = self.op_rect_line_width)
        self.setup_item_signals(self.rect)

        #separator line between the title and 
        line = goo.polyline_new_line(self, 0, 17, self.op_width, 17, 
                line_width = 1.0,
                stroke_color_rgba = self.op_border_color)
        self.setup_item_signals(line)
        
        #the title
        text = goo.Text(parent = self, 
                text = self.op_name, 
                x = self.op_width/2, 
                y = 9, 
                width = -1,
                anchor = gtk.ANCHOR_CENTER,
                alignment = pango.ALIGN_CENTER,
                font = "Sans Bold 12")
        self.setup_item_signals(text)

        self.dragging = False
        self.connecting = False


        self.set_attributes()


    def set_attributes(self):
        """
        update/create the attribute text items
        """
        try:
            #delete them if they already exist
            num = self.get_n_children()
            for i in xrange(3, num):
                self.remove_child(3)
        except Exception, e:
            print(e.message)
        ypos = 20
        for key in (self.op_attr_order + 
                [a for a in self.op_attributes.iterkeys() 
                    if a not in self.op_attr_order]):
            text = self.get_attribute_text_item(key, self.op_width/2, ypos)
            self.setup_item_signals(text)
            b = text.get_bounds()
            ypos += b.y2 - b.y1

    def get_attribute_text_item(self, key, xpos, ypos):
        """
        Create the text item - subclasses may overwrite this
        """
        value = self.op_attributes[key]
        text_item = goo.Text(parent = self,
                text = "<i>"+key+"</i>: "+str(value),
                x = xpos,
                y = ypos,
                width = self.op_width,
                anchor = gtk.ANCHOR_NORTH,
                alignment = pango.ALIGN_CENTER,
                font = "Sans 8",
                use_markup = True)
        return text_item


    def set_connection(self, parent):
        """
        Connect two collections
        """
        if ((len(self.op_outputs)+1 > self.op_n_outputs) or 
                (len(parent.op_operands)+1 > parent.op_n_operands) or
                (parent in self.op_outputs) or
                (self in parent.op_operands)):
            return
        self.op_outputs.append(parent)
        parent.op_operands.append(self)
        self.update_connections() #update arrows

    def unset_connection(self, parent):
        """
        severe the connection between two collections
        """
        try:
            self.op_outputs.remove(parent)
        except IndexError:
            pass
        try:
            parent.op_operands.remove(self)
        except IndexError:
            pass

    def update_connections(self):
        """
        update/add arrows according to the connections the item has
        """
        for parent in self.op_outputs:
            self.editor.add_arrow(parent, self)
        for child in self.op_operands:
            self.editor.add_arrow(self, child)


    def delete(self):
        """
        delete an item
        """
        for parent in copy.copy(self.op_outputs):
            self.editor.remove_arrow((parent, self))
        for child in copy.copy(self.op_operands):
            self.editor.remove_arrow((self, child))
        self.remove()

    def setup_item_signals(self, item):
        """
        set handlers for moving around, selecting
        """
        item.connect("motion_notify_event", self.on_motion_notify)
        item.connect("button_press_event", self.on_button_press)
        item.connect("button_release_event", self.on_button_release)

    def on_motion_notify(self, item, target, event):
        """
        moving around the item
        """
        if (self.dragging == True) and (event.state & gtk.gdk.BUTTON1_MASK):
            new_x = event.x
            new_y = event.y
            self.translate(new_x - self.drag_x, new_y - self.drag_y)
            self.update_connections()
        return True

    def on_button_press(self, item, target, event):
        if (event.button == 1) and (event.state & gtk.gdk.SHIFT_MASK):
            self.delete()
        elif event.button == 1:
            self.drag_x = event.x
            self.drag_y = event.y

            #change the cursor
            fleur = gtk.gdk.Cursor(gtk.gdk.FLEUR)
            canvas = item.get_canvas ()
            #grab the pointer
            canvas.pointer_grab(item,
                    gtk.gdk.POINTER_MOTION_MASK | gtk.gdk.BUTTON_RELEASE_MASK,
                    fleur, event.time)
            self.dragging = True
        elif event.button == 3:
            #create connections between operands
            fleur = gtk.gdk.Cursor(gtk.gdk.FLEUR)
            canvas = item.get_canvas ()
            canvas.pointer_grab(item,
                    gtk.gdk.POINTER_MOTION_MASK | gtk.gdk.BUTTON_RELEASE_MASK,
                    fleur, event.time)
            self.connecting = True

    def on_button_release(self, item, target, event):
        if event.button == 1:
            canvas = item.get_canvas()
            canvas.pointer_ungrab(item, event.time)
            self.dragging = False
            self.update_connections() 
            #the focus change
            self.editor.focus_changed(self)
        elif event.button == 3:
            #connection created between items - show the arrow,
            #and set the connection
            canvas = item.get_canvas()
            canvas.pointer_ungrab(item, event.time)
            x, y = canvas.convert_from_item_space(target, event.x, event.y)
            clicked = canvas.get_item_at(x, y, False)
            if clicked != None:
                parent = clicked.get_parent()
                if isinstance(parent, Operator):
                    self.set_connection(parent)
            self.connecting = False

    def get_properties_frame(self):
        """
        subclasses should overwrite this one
        this function should return a frame to set collection attributes
        """
        frame = self.editor.helpframe
        return frame

class RootGroup(Operator):
    """
    The root collection - change the name with it
    """
    op_n_outputs = 0
    op_n_operands = 1
    op_name = _("Collection name")
    op_width = 150
    op_height = 32
    op_rect_line_width = 2.0
    op_fill_color = 0xc2ddfd80
    op_border_color = 0x1c73a9ff
    
    def __init__(self, editor, parent, name, x = 0, y = 0):
        self.name = name
        Operator.__init__(self, editor, parent, x, y)

    def view_init(self):
        """simpler look, no need for attributes and separator line"""
        self.rect = goo.Rect(parent = self, 
                x = 0, 
                y = 0,
                width = self.op_width,
                height = self.op_height,
                fill_color_rgba = self.op_fill_color,
                stroke_color_rgba = self.op_border_color,
                radius_x = 5,
                radius_y = 5,
                line_width = self.op_rect_line_width)
        self.setup_item_signals(self.rect)

        self.set_name_view()
        self.dragging = False
        self.connecting = False
        
    def set_name_view(self):
        text = goo.Text(parent = self, 
                text = self.name, 
                x = 75, 
                y = 16, 
                width = -1,
                anchor = gtk.ANCHOR_CENTER,
                alignment = pango.ALIGN_CENTER,
                font = "Sans Bold 12")
        self.setup_item_signals(text)

    def get_properties_frame(self):
        frame = gtk.Frame("Details")

        vbox1 = gtk.VBox()
        vbox1.pack_start(gtk.Label(_("Name")+': '), False, False)
        name_entry = gtk.Entry()
        name_entry.set_text(self.name)
        name_entry.connect('changed', self.set_name)
        vbox1.pack_start(name_entry, False, False)

        frame.add(vbox1)
        frame.show_all()
        return frame

    def set_name(self, widget):
        """set the name of the collection"""
        self.name = widget.get_text()
        self.remove_child(1)
        self.set_name_view()

    def get_name(self):
        """get the new/old name of the collection"""
        return self.name

class ReferenceOperator(Operator):
    op_name = _('Reference')
    op_type = ec.Reference
    op_width = 150
    op_height = 80
    op_n_operands = 0
    op_rect_line_width = 2.0
    op_fill_color = 0xc2ddfd80
    op_border_color = 0x1c73a9ff
    op_attr_order = ['reference', 'namespace']
    
    def view_init(self):
        self.op_attributes = {'reference': '', 'namespace': 'Collections'}

        self.rect = goo.Rect(parent = self, 
                x = 0, 
                y = 0,
                width = self.op_width,
                height = self.op_height,
                fill_color_rgba = self.op_fill_color,
                stroke_color_rgba = self.op_border_color,
                radius_x = 10,
                radius_y = 10,
                line_width = self.op_rect_line_width,
                line_dash = goo.LineDash([5.0,5.0]))
        self.setup_item_signals(self.rect)
        
        text = goo.Text(parent = self, 
                text = self.op_name, 
                x = self.op_width/2, 
                y = 9, 
                width = -1,
                anchor = gtk.ANCHOR_CENTER,
                alignment = pango.ALIGN_CENTER,
                font = "Sans Bold 12")
        self.setup_item_signals(text)
        
        line = goo.polyline_new_line(self, 0, 17, self.op_width, 17, 
                line_width=1.0, stroke_color_rgba=self.op_border_color)
        self.setup_item_signals(line)
        self.dragging = False
        self.connecting = False
    
    def get_attribute_text_item(self, key, xpos, ypos):
        value = self.op_attributes[key]
        text = ''
        font = "Sans 8"
        if key == 'reference':
            text = "<b>%s</b>" % (value)
            font = "Sans 9"
        elif key == 'namespace':
            text = "<i>%s %s</i>" % (_('from'), value)
        text_item = goo.Text(parent = self,
                text = text,
                x = xpos,
                y = ypos,
                width = self.op_width,
                anchor = gtk.ANCHOR_NORTH,
                alignment = pango.ALIGN_CENTER,
                font = font,
                use_markup = True)
        return text_item

    def get_properties_frame(self):
        frame = gtk.Frame("Details")
        table = gtk.Table(rows = 5, columns = 1, homogeneous = True)
        table.set_row_spacings(5)
        table.set_col_spacings(5)

        self.namespace = gtk.combo_box_new_text()
        [self.namespace.append_text(ns) for ns in ('Collections', 'Playlists')]
        if self.op_attributes['namespace'] == 'Playlists':
            self.namespace.set_active(1)
        else:
            self.namespace.set_active(0)
        table.attach(gtk.Label(_("Namespace")+": "), 0, 1, 0, 1)
        table.attach(self.namespace, 0, 1, 1, 2)
        self.namespace.connect('changed', self.attribute_changed, 'namespace')

        self.reference = gtk.combo_box_entry_new_text()
        self.fill_collection_list(self.op_attributes['reference'])
        table.attach(gtk.Label(_("Collection")+": "), 0, 1, 3, 4)
        table.attach(self.reference, 0, 1, 4, 5)
        self.reference.connect('changed', self.attribute_changed, 'reference')
         
        frame.add(table)
        frame.show_all()
        return frame
    
    def fill_collection_list(self, active = ''):
        #remove the old ones
        [self.reference.remove_text(0)
                for ind in xrange(len(self.reference.get_model()))]
        client = self.editor.plugin.control.client
        ns = self.namespace.get_active_text()
        collections = client.get_collections(ns) 
        active_set = False
        for coll in collections:
            self.reference.append_text(coll)
            if active == coll:
                self.reference.set_active(collections.index(coll))
                active_set = True
        if not active_set and active:
            self.reference.prepend(active)
            self.reference.set_active(0)

    def attribute_changed(self, widget, key):
        if key in ('reference', 'namespace'):
            text = widget.get_active_text()
            self.op_attributes[key] = text
            if key == 'namespace':
                self.fill_collection_list()
        self.set_attributes()
    
class UniverseOperator(Operator):
    op_type = ec.Universe
    op_name = _("All Media")
    op_width = 150
    op_height = 32
    op_n_operands = 0
    op_rect_line_width = 2.0
    op_fill_color = 0xc2ddfd80
    op_border_color = 0x1c73a9ff

    def view_init(self):

        self.rect = goo.Rect(parent = self, 
                x = 0, 
                y = 0,
                width = self.op_width,
                height = self.op_height,
                fill_color_rgba = self.op_fill_color,
                stroke_color_rgba = self.op_border_color,
                radius_x = 10,
                radius_y = 10,
                line_width = self.op_rect_line_width,
                line_dash = goo.LineDash([5.0, 5.0]))
        self.setup_item_signals(self.rect)

        text = goo.Text(parent = self, 
                text = self.op_name, 
                x = 75, 
                y = 16, 
                width = -1,
                anchor = gtk.ANCHOR_CENTER,
                alignment = pango.ALIGN_CENTER,
                font = "Sans Bold 12")
        self.setup_item_signals(text)
        self.dragging = False
        self.connecting = False

class _MatchEqualsOperator(Operator):

    op_n_operands = 1
    op_str = '='
    op_attr_order = ['field', 'value', 'case-sensitive']

    def view_init(self):
        self.op_attributes = {'field': '', 'value': '',
                'case-sensitive': 'true'}
        Operator.view_init(self)

    def get_attribute_text_item(self, key, xpos, ypos):
        value = self.op_attributes[key]
        text = ''
        font = "Sans 8"
        if key == 'field':
            text = "<i>%s %s</i>" % (value, self.op_str) 
        elif key == 'value':
            text = value
        elif key == 'case-sensitive':
            font = "Sans 7"
            if value == 'true':
                text = _("case sensitive")
            else:
                text = _("case insensitive")
        text_item = goo.Text(parent = self,
                text = text,
                x = xpos,
                y = ypos,
                width = self.op_width,
                anchor = gtk.ANCHOR_NORTH,
                alignment = pango.ALIGN_CENTER,
                font = font,
                use_markup = True)
        return text_item
    
    def get_properties_frame(self):
        frame = gtk.Frame("Details")
        table = gtk.Table(rows = 7, columns = 1, homogeneous = True)
        table.set_row_spacings(5)
        table.set_col_spacings(5)

        field_entry = get_property_combo(self.op_attributes['field'])
        table.attach(gtk.Label(_("Property")+": "), 0, 1, 0, 1)
        table.attach(field_entry, 0, 1, 1, 2)
        field_entry.connect('changed', self.attribute_changed, 'field')

        value_entry = gtk.Entry()
        value_entry.set_text(self.op_attributes['value'])
        value_entry.set_text(self.op_attributes['value'])
        table.attach(gtk.Label(_("Value")+": "), 0, 1, 3, 4)
        table.attach(value_entry, 0, 1, 4, 5)
        value_entry.connect('changed', self.attribute_changed, 'value')

        case_sensitive = gtk.CheckButton(_("case sensitive").capitalize())
        if self.op_attributes['case-sensitive'] == 'true':
            case_sensitive.set_active(True)
        else:
            case_sensitive.set_active(False)
        table.attach(case_sensitive, 0, 1, 6, 7)
        case_sensitive.connect('toggled', self.attribute_changed,
                'case-sensitive')

        frame.add(table)
        frame.show_all()
        return frame

    def attribute_changed(self, widget, key):
        if key == 'value':
            text = widget.get_text()
            self.op_attributes[key] = text
        elif key == 'field':
            text = widget.get_active_text()
            self.op_attributes[key] = text
        elif key == 'case-sensitive':
            self.op_attributes['case-sensitive'] = str(widget.get_active()).lower()
        self.set_attributes()


class EqualsOperator(_MatchEqualsOperator):
    op_name = _("Equals")
    op_type = ec.Equals

class MatchOperator(_MatchEqualsOperator):
    op_name = _("Match")
    op_type = ec.Match
    op_str = '~'

class _SmallerGreaterOperator(Operator):
    op_n_operands = 1
    op_str = '&lt;'
    op_attr_order = ['field', 'value']

    def view_init(self):
        self.op_attributes = {'field': '', 'value': ''}
        Operator.view_init(self)
    
    def get_attribute_text_item(self, key, xpos, ypos):
        value = self.op_attributes[key]
        text = ''
        if key == 'field':
            text = "<i>%s %s</i>" % (value, self.op_str) 
        elif key == 'value':
            text = value
        text_item = goo.Text(parent = self,
                text = text,
                x = xpos,
                y = ypos,
                width = self.op_width,
                anchor = gtk.ANCHOR_NORTH,
                alignment = pango.ALIGN_CENTER,
                font = "Sans 8",
                use_markup = True)
        return text_item
    
    def get_properties_frame(self):
        frame = gtk.Frame("Details")
        table = gtk.Table(rows = 5, columns = 1, homogeneous = True)
        table.set_row_spacings(5)
        table.set_col_spacings(5)

        field_entry = get_property_combo(self.op_attributes['field'])
        table.attach(gtk.Label(_("Property")+": "), 0, 1, 0, 1)
        table.attach(field_entry, 0, 1, 1, 2)
        field_entry.connect('changed', self.attribute_changed, 'field')

        value_entry = gtk.Entry()
        value_entry.set_text(self.op_attributes['value'])
        table.attach(gtk.Label(_("Value")+": "), 0, 1, 3, 4)
        table.attach(value_entry, 0, 1, 4, 5)
        value_entry.connect('changed', self.attribute_changed, 'value')

        frame.add(table)
        frame.show_all()
        return frame

    def attribute_changed(self, widget, key):
        if key == 'value':
            text = widget.get_text()
            self.op_attributes[key] = text
        elif key == 'field':
            text = widget.get_active_text()
            self.op_attributes[key] = text
        self.set_attributes()

class GreaterOperator(_SmallerGreaterOperator):
    op_name = _("Greater")
    op_type = ec.Greater
    op_str = '&gt;'

class SmallerOperator(_SmallerGreaterOperator):
    op_name = _("Smaller")
    op_type = ec.Smaller

class HasOperator(Operator):
    op_name = _("Has")
    op_type = ec.Has
    op_n_operands = 1
    
    def view_init(self):
        self.op_attributes = {'field': '' }
        Operator.view_init(self)

    def get_properties_frame(self):
        frame = gtk.Frame("Details")
        table = gtk.Table(rows = 2, columns = 1)
        table.set_row_spacings(5)
        table.set_col_spacings(5)

        field_entry = get_property_combo(self.op_attributes['field'])
        table.attach(gtk.Label(_("Property")+": "), 0, 1, 0, 1)
        table.attach(field_entry, 0, 1, 1, 2)
        field_entry.connect('changed', self.attribute_changed, 'field')

        frame.add(table)
        frame.show_all()
        return frame

    def get_attribute_text_item(self, key, xpos, ypos):
        value = self.op_attributes[key]
        text = "<i>%s:</i> %s" % (_("Property"), value)
        text_item = goo.Text(parent = self,
                text = text,
                x = xpos,
                y = ypos,
                width = self.op_width,
                anchor = gtk.ANCHOR_NORTH,
                alignment = pango.ALIGN_CENTER,
                font = "Sans 8",
                use_markup = True)
        return text_item
    
    def attribute_changed(self, widget, key, lw = None):
        if key == 'field':
            text = widget.get_active_text()
            self.op_attributes[key] = text
        self.set_attributes()

class _SetOperator(Operator):
    op_height = 40
    op_border_color = 0x028117ff
    op_fill_color = 0x61ab2f80


class AndOperator(_SetOperator):
    op_name = _("And")
    op_type = ec.Intersection

class NotOperator(_SetOperator):
    op_name = _("Not")
    op_type = ec.Complement
    op_n_operands = 1

class OrOperator(_SetOperator):
    op_name = _("Or")
    op_type = ec.Union

class _ListOperator(Operator):
    op_border_color = 0xce3030ff
    op_fill_color = 0xe64a4a80
    
    def create_collview(self, coll):
        plugin = self.editor.plugin
        view_format = plugin.get_config('list')
        if ('<id>' not in view_format):
            view_format = '<id>|'+view_format
        collview = IDListView(plugin, view_format)
        collview.set_default_order_format(plugin.get_config('default_order'))
        collview.enable_dnd(True, True)

        [coll.ids.append(song_id) for song_id in self.op_ids]
        collview.set_coll(coll)
        model = collview.get_model()
        collview.ids = self.op_ids
        model.connect('row-deleted',
                lambda model,path: self.attribute_changed(collview, 'ids'))
        model.connect('row-inserted',
                lambda model,path,iter: self.attribute_changed(collview, 'ids'))
        model.connect('rows-reordered',
                lambda model,path,iter,new_order: self.attribute_changed(collview, 'ids'))
        scroll = gtk.ScrolledWindow()
        scroll.set_policy( gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        scroll.add(collview)
        return scroll

    def get_jumplist_entry(self):
        jumplist = gtk.combo_box_entry_new_text()
        client = self.editor.plugin.control.client
        collections = client.get_collections('Playlists') 
        active = self.op_attributes['jumplist']
        for coll in collections:
            jumplist.append_text(coll)
            if active == coll:
                jumplist.set_active(collections.index(coll))
        if (jumplist.get_active() == -1) and (active != ''):
            jumplist.prepend(active)
            jumplist.set_active(0)
        return jumplist


class PShuffleOperator(_ListOperator):
    op_name = _("Party Shuffle")
    op_type = ec.PShuffle
    op_n_operands = 1
    op_attr_order = ['upcoming', 'history', 'jumplist']
    
    def view_init(self):
        self.op_attributes = {'upcoming': 30, 'history': 0, 'jumplist': '' }
        self.op_ids = []
        _ListOperator.view_init(self)

    def get_properties_frame(self):
        frame = gtk.Frame("Details")
        table = gtk.Table(rows = 5, columns = 2)
        table.set_row_spacings(5)
        table.set_col_spacings(5)

        upcoming = gtk.SpinButton(climb_rate= 1.0)
        upcoming.set_range(0, 9999)
        upcoming.set_increments(1, 5)
        upcoming.set_value(int(self.op_attributes['upcoming']))
        table.attach(gtk.Label(_("Upcoming")+": "), 0, 1, 0, 1,
                xoptions = 0, yoptions = 0)
        table.attach(upcoming, 1, 2, 0, 1, xoptions = 0, yoptions = 0)
        upcoming.connect('value-changed', self.attribute_changed, 'upcoming')

        history = gtk.SpinButton(climb_rate = 1.0)
        history.set_range(0, 9999)
        history.set_increments(1, 5)
        history.set_value(int(self.op_attributes['history']))
        table.attach(gtk.Label(_("History")+": "), 0, 1, 1, 2,
                xoptions = 0, yoptions = 0)
        table.attach(history, 1, 2, 1, 2, xoptions = 0, yoptions = 0)
        history.connect('value-changed', self.attribute_changed, 'history')

        jumplist = self.get_jumplist_entry()
        table.attach(gtk.Label(_("Jumplist")+": "), 0, 2, 2, 3,
                xoptions = gtk.FILL, yoptions = 0)
        table.attach(jumplist, 0, 2, 3, 4, xoptions = gtk.FILL, yoptions = 0)
        jumplist.connect('changed', self.attribute_changed, 'jumplist')

        coll = ec.PShuffle(ec.IDList())
        collview = self.create_collview(coll)
        table.attach(collview, 0, 2, 4, 5)
        
        frame.add(table)
        frame.show_all()
        return frame

    def attribute_changed(self, widget, key):
        if key in ('upcoming', 'history'):
            val = widget.get_value_as_int()
            self.op_attributes[key] = val
        elif key == 'jumplist':
            text = widget.get_active_text()
            self.op_attributes[key] = text
        elif key == 'ids':
            self.op_ids = widget.get_ids()
        self.set_attributes()

class QueueOperator(_ListOperator):
    op_name = _("Queue")
    op_type = ec.Queue
    op_n_operands = 0
    op_attr_order = ['history', 'jumplist']

    def view_init(self):
        self.op_attributes = {'history': 0, 'jumplist': '' }
        self.op_ids = []
        _ListOperator.view_init(self)
    
    def get_properties_frame(self):
        frame = gtk.Frame("Details")
        table = gtk.Table(rows = 4, columns = 2)
        table.set_row_spacings(5)
        table.set_col_spacings(5)

        history = gtk.SpinButton(climb_rate = 1.0)
        history.set_range(0, 9999)
        history.set_increments(1, 5)
        history.set_value(int(self.op_attributes['history']))
        table.attach(gtk.Label(_("History")+": "), 0, 1, 0, 1,
                xoptions = gtk.FILL, yoptions = 0)
        table.attach(history, 1, 2, 0, 1, xoptions = gtk.FILL, yoptions = 0)
        history.connect('value-changed', self.attribute_changed, 'history')

        jumplist = self.get_jumplist_entry()
        table.attach(gtk.Label(_("Jumplist")+": "), 0, 2, 1, 2,
                xoptions = gtk.FILL, yoptions = 0)
        table.attach(jumplist, 0, 2, 2, 3, xoptions = gtk.FILL, yoptions = 0)
        jumplist.connect('changed', self.attribute_changed, 'jumplist')
        
        coll = ec.Queue()
        collview = self.create_collview(coll)
        table.attach(collview, 0, 2, 3, 4)
        
        frame.add(table)
        frame.show_all()
        return frame

    def attribute_changed(self, widget, key):
        if key == 'history':
            val = widget.get_value_as_int()
            self.op_attributes[key] = val
        elif key == 'jumplist':
            text = widget.get_active_text()
            self.op_attributes[key] = text
        elif key == 'ids':
            self.op_ids = widget.get_ids()
        self.set_attributes()


class IDListOperator(_ListOperator):
    op_name = _("ID List")
    op_type = ec.IDList
    op_n_operands = 0

    def view_init(self):
        self.op_attributes = {'jumplist': '' }
        self.op_ids = []
        _ListOperator.view_init(self)
    
    def get_properties_frame(self):
        frame = gtk.Frame("Details")
        table = gtk.Table(rows = 3, columns = 1)
        table.set_row_spacings(5)
        table.set_col_spacings(5)

        jumplist = self.get_jumplist_entry()
        table.attach(gtk.Label(_("Jumplist")+": "), 0, 1, 0, 1,
                xoptions = gtk.FILL, yoptions = 0)
        table.attach(jumplist, 0, 1, 1, 2, xoptions = gtk.FILL, yoptions = 0)
        jumplist.connect('changed', self.attribute_changed, 'jumplist')
        
        coll = ec.IDList()
        collview = self.create_collview(coll)
        table.attach(collview, 0, 1, 2, 3)
        
        frame.add(table)
        frame.show_all()
        return frame

    def attribute_changed(self, widget, key):
        if key == 'jumplist':
            text = widget.get_active_text()
            self.op_attributes[key] = text
        elif key == 'ids':
            self.op_ids = widget.get_ids()
        self.set_attributes()

